﻿using System;
using System.Collections.Generic;
using Framework.Audio;
using UnityEngine;
using AudioType = Framework.Audio.AudioType;


namespace Audio
{
    /// <summary>
    /// Foldcc
    /// 通用音频管理器
    /// </summary>
    public class BaseAudioManager : MonoBehaviour
    {

        private static readonly int _MAX_TRACK = 20;
        protected BaseAudioManager()
        {
            this._AudioFree    = new List<AudioTrack>();
            this._AudioPlaying = new List<AudioTrack>();
            this._AudioVolume  = new Dictionary<ushort, float>();
        }


        protected List<AudioTrack>          _AudioFree;
        protected List<AudioTrack>          _AudioPlaying;
        protected Dictionary<ushort, float> _AudioVolume;

        protected string SourcePath;

        private bool _isActiveUpdater = true;

        public IAudioSourceHandler AudioSourceHandler;
        
        public virtual void Init(IAudioSourceHandler audioSourceHandler)
        {
            this.AudioSourceHandler = audioSourceHandler;
        }

        protected virtual void DoUpdate()
        {
            // UtilProfiler.Instance.Start("AudioManager");
            if (this._isActiveUpdater == false)
            {
                return;
            }
            for (int i = this._AudioPlaying.Count - 1; i >= 0; i--)
            {
                if (this._AudioPlaying[i].IsDone)
                {
                    var audioTrack = this._AudioPlaying[i];
                    this._AudioPlaying.RemoveAt(i);
                    audioTrack.OverReset();
                    if (this._AudioFree.Count < _MAX_TRACK)
                        this._AudioFree.Add(audioTrack);
                    else
                        Destroy(audioTrack.gameObject);
                }
            }
            // UtilProfiler.Instance.End();
        }

        public AudioTrack CreateAudio(ushort audioGroup)
        {
            var obj         = new GameObject {name = "Audio_Track" + audioGroup};
            var audioSource = obj.AddComponent<AudioSource>();
            obj.transform.SetParent(this.transform);
            return obj.AddComponent<AudioTrack>().Init(audioSource, audioGroup , this.AudioSourceHandler);
        }

        /// <summary>
        /// 设置音频文件的根目录
        /// </summary>
        /// <param name="path"></param>
        public void SetSourcePath(string path) { this.SourcePath = path; }

        public void SetGroupVolume(AudioType audioGroup, float volume)
        {
            ushort audioShort = (ushort)audioGroup;
            this._AudioVolume[audioShort] = Mathf.Clamp(volume, 0, 1);
            var audios = this.GetPlayingAudio(audioShort);
            foreach (var audioTrack in audios)
            {
                audioTrack.SetVolumeOffset(this._AudioVolume[audioShort]);
            }
        }

        protected AudioTrack BasePlay(string audioName, float volume = 1, float spatialBlend = 0, float inTime = 0, AudioType audioGroup = AudioType.SOUND, bool isLoop = false)
        {
            ushort audioShort = (ushort)audioGroup;
            var player = this.GetFreePlayer(audioShort);
            if (!this._AudioVolume.ContainsKey(audioShort))
            {
                //默认值
                this._AudioVolume[audioShort] = 1;
            }
            player.AudioSource.spatialBlend = spatialBlend;
            player.Play(audioName, this._AudioVolume[audioShort], volume, inTime, isLoop);
            this._AudioPlaying.Add(player);
            return player;
        }

        public void PausePlayers(AudioType audioGroup, bool isPause, float outTime = 0)
        {
            ushort audioShort = (ushort)audioGroup;
            var players = this.GetPlayingAudio(audioShort);
            foreach (var audioPlayer in players)
            {
                if (isPause)
                    audioPlayer.Pause(outTime);
                else
                    audioPlayer.UnPause(outTime);
            }
        }

        public void StopPlayers(string audioName, float outTime = 0)
        {
            foreach (var audioPlayer in this._AudioPlaying)
            {
                if (audioPlayer.AudioName == audioName)
                {
                    audioPlayer.Kill(outTime);
                }
            }
        }

        public void StopPlayers(AudioType audioGroup, float outTime = 0)
        {
            ushort audioShort = (ushort)audioGroup;
            var players = this.GetPlayingAudio(audioShort);
            foreach (var audioPlayer in players)
            {
                audioPlayer.Kill(outTime);
            }
        }

        public void StopAllPlayer(float outTime = 0)
        {
            foreach (var audioPlayer in this._AudioPlaying)
            {
                audioPlayer.Kill(outTime);
            }
        }

        public void PauseAllPlayer(bool isPause, float outTime = 0)
        {
            foreach (var audioPlayer in this._AudioPlaying)
            {
                if (isPause)
                {
                    audioPlayer.Pause(outTime);
                }
                else
                {
                    audioPlayer.UnPause(outTime);
                }
            }
        }

        public AudioTrack GetFreePlayer(ushort audioGroup)
        {
            foreach (var audioPlayer in this._AudioFree)
            {
                if (audioPlayer.AudioGroup == audioGroup)
                {
                    this._AudioFree.Remove(audioPlayer);
                    return audioPlayer;
                }
            }
            return this.CreateAudio(audioGroup);
        }

        public List<AudioTrack> GetPlayingAudio(ushort audioGroup)
        {
            List<AudioTrack> audioPlayers = new List<AudioTrack>();
            foreach (var audioPlayer in this._AudioPlaying)
            {
                if (audioPlayer.AudioGroup == audioGroup)
                {
                    audioPlayers.Add(audioPlayer);
                }
            }

            return audioPlayers;
        }
        
        private void OnApplicationPause(bool pauseStatus) { this._isActiveUpdater = !pauseStatus; }

    }
}